package org.cosmact.designer.vxml.gefeditor.router;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;
import org.cosmact.vxml.model.Dialog;
import org.cosmact.vxml.model.DialogConnection;

/**
 * A path indicate a dialog sequences in a flow by their connection
 * relationship.
 * 
 *@author hsieh 234aini@gmail.com
 * 
 */
public class Path {

    private static Logger logger = Logger.getLogger(Path.class);

    private List<Dialog> nodes = new ArrayList<Dialog>();

    private final Dialog head;

    private Dialog lastNode;

    private Dialog backloopDialog;

    /**
     * Create a new path with the head as the path first node.
     * 
     * @param head
     */
    public Path(final Dialog head) {
	if (head == null)
	    throw new IllegalArgumentException("Path head");
	this.head = head;
	appendNode(head);
    }

    /**
     * Append a new node to this path.
     * 
     * @param node
     */
    public void appendNode(Dialog node) {
	if (node == null) {
	    logger.debug("Can't append a null to path");
	}
	if (!nodes.contains(node)) {
	    nodes.add(node);
	    this.lastNode = node;
	    // set the back loop flag
	    backloopDialog = null;
	} else {
	    // set the back loop flag
	    backloopDialog = node;
	}
    }

    /**
     * Only for browsing the node.
     * 
     * @return The return list is unmodified.
     */
    public List<Dialog> getNodes() {
	return Collections.unmodifiableList(nodes);
    }

    /**
     * Create a new path same with this path. They have same node sequence.
     * 
     * @return A new path.
     */
    public Path getCopy() {
	Path path = new Path(head);
	for (Iterator<Dialog> iterator = nodes.iterator(); iterator.hasNext();) {
	    Dialog type = iterator.next();
	    path.appendNode(type);
	}
	return path;
    }

    /**
     * Return ture only when source path and target path are all not null and
     * have same node sequence.
     * 
     * @param target
     * @return False if source or targer is null.
     */
    public boolean isSamePath(Path target) {
	if (target == null) {
	    return false;
	}
	List<Dialog> sList = getNodes();
	List<Dialog> tList = target.getNodes();
	if (sList.size() != tList.size())
	    return false;
	for (int i = 0; i < sList.size(); i++) {
	    Dialog s = sList.get(i);
	    Dialog t = tList.get(i);
	    if (!s.equals(t)) {
		return false;
	    }
	}
	return true;
    }

    /**
     * Get the head of the path.
     * 
     * @return
     */
    public Dialog getHead() {
	return head;
    }

    /**
     * Get the last node of the path.
     * 
     * @return
     */
    public Dialog getLastNode() {
	return lastNode;
    }

    /**
     * If the last node target nodes are all contained by this path, this path
     * is end.
     * 
     * @return
     */
    public boolean isEnd() {
	if (isBackloop()) {
	    return true;
	}

	Dialog last = getLastNode();
	if (last.getSourceConnections().isEmpty()) {
	    return true;
	}
	for (DialogConnection connection : last.getSourceConnections()) {
	    if (!getNodes().contains(connection.getTarget()))
		return false;
	}
	return true;
    }

    @Override
    public String toString() {
	StringBuilder builder = new StringBuilder();
	for (Iterator<Dialog> iterator = nodes.iterator(); iterator.hasNext();) {
	    Dialog type = iterator.next();
	    builder.append(type.getId() + "--->");
	}
	if (isBackloop())
	    builder.append("<--" + getBackloopDialog().getId());
	return builder.toString();
    }

    public boolean isBackloop() {
	return backloopDialog != null;
    }

    public Dialog getBackloopDialog() {
	return backloopDialog;
    }
}
